import PyPDF2
import os
import sys
from pathlib import Path
import tkinter as tk
from tkinter import filedialog, messagebox, simpledialog, ttk

def resource_path(relative_path):
    """获取资源的绝对路径，适用于PyInstaller打包后的环境"""
    try:
        # PyInstaller创建的临时文件夹
        base_path = sys._MEIPASS
    except Exception:
        base_path = os.path.abspath(".")

    return os.path.join(base_path, relative_path)

def is_valid_pdf(file_path):
    """检查文件是否为有效的PDF文件"""
    try:
        with open(file_path, 'rb') as f:
            # 尝试读取文件头以验证是否为PDF
            header = f.read(4)
            return header == b'%PDF'
    except:
        return False
    return False

class PDFMergerGUI:
    def __init__(self, root):
        self.root = root
        self.root.title("PDF文件合并（单面扫描专用）v1.0")
        self.root.geometry("600x400")
        self.root.resizable(False, False)

        # 设置程序图标
        try:
            icon_path = resource_path("1.ico")
            # 检查图标文件是否存在
            if os.path.exists(icon_path):
                self.root.iconbitmap(icon_path)
            else:
                print(f"图标文件不存在: {icon_path}")
        except Exception as e:
            print(f"无法加载图标: {str(e)}")
            # 如果图标加载失败，继续运行程序但不显示图标

        # 初始化变量
        self.pdf1_path = tk.StringVar()
        self.pdf2_path = tk.StringVar()
        self.output_path = tk.StringVar()

        self.setup_ui()

    def setup_ui(self):
        # 主框架
        main_frame = ttk.Frame(self.root, padding="20")
        main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))

        # 标题
        title_label = ttk.Label(main_frame, text="PDF文件合并工具", font=("Arial", 16, "bold"))
        title_label.grid(row=0, column=0, columnspan=3, pady=(0, 20))

        # 第一个PDF文件选择
        ttk.Label(main_frame, text="第一个PDF文件:").grid(row=1, column=0, sticky=tk.W, pady=5)
        ttk.Entry(main_frame, textvariable=self.pdf1_path, width=50).grid(row=1, column=1, padx=5)
        ttk.Button(main_frame, text="浏览...", command=self.select_pdf1).grid(row=1, column=2, padx=5)

        # 第二个PDF文件选择
        ttk.Label(main_frame, text="第二个PDF文件:").grid(row=2, column=0, sticky=tk.W, pady=5)
        ttk.Entry(main_frame, textvariable=self.pdf2_path, width=50).grid(row=2, column=1, padx=5)
        ttk.Button(main_frame, text="浏览...", command=self.select_pdf2).grid(row=2, column=2, padx=5)

        # 输出文件选择
        ttk.Label(main_frame, text="输出文件路径:").grid(row=3, column=0, sticky=tk.W, pady=5)
        ttk.Entry(main_frame, textvariable=self.output_path, width=50).grid(row=3, column=1, padx=5)
        ttk.Button(main_frame, text="浏览...", command=self.select_output).grid(row=3, column=2, padx=5)

        # 合并按钮
        self.merge_button = ttk.Button(main_frame, text="开始合并", command=self.merge_pdfs, state=tk.DISABLED)
        self.merge_button.grid(row=4, column=0, columnspan=3, pady=20)

        # 状态栏
        self.status_var = tk.StringVar()
        self.status_var.set("请选择要合并的PDF文件")
        status_bar = ttk.Label(self.root, textvariable=self.status_var, relief=tk.SUNKEN, anchor=tk.W)
        status_bar.grid(row=1, column=0, sticky=(tk.W, tk.E))

        # 配置网格权重
        self.root.columnconfigure(0, weight=1)
        self.root.rowconfigure(0, weight=1)
        main_frame.columnconfigure(1, weight=1)

        # 绑定事件以启用/禁用合并按钮
        self.pdf1_path.trace_add('write', self.check_inputs)
        self.pdf2_path.trace_add('write', self.check_inputs)
        self.output_path.trace_add('write', self.check_inputs)

    def check_inputs(self, *args):
        """检查所有输入是否已填写，以启用或禁用合并按钮"""
        if self.pdf1_path.get() and self.pdf2_path.get() and self.output_path.get():
            self.merge_button.config(state=tk.NORMAL)
        else:
            self.merge_button.config(state=tk.DISABLED)

    def select_pdf1(self):
        """选择第一个PDF文件"""
        file_path = self.select_file("选择第一个PDF文件")
        if file_path:
            self.pdf1_path.set(file_path)
            # 自动设置输出文件名
            if not self.output_path.get() and self.pdf1_path.get():
                first_pdf_dir = os.path.dirname(self.pdf1_path.get())
                first_pdf_name = os.path.splitext(os.path.basename(self.pdf1_path.get()))[0]
                default_name = f"{first_pdf_name}_合并.pdf"
                self.output_path.set(os.path.join(first_pdf_dir, default_name))

    def select_pdf2(self):
        """选择第二个PDF文件"""
        file_path = self.select_file("选择第二个PDF文件")
        if file_path:
            self.pdf2_path.set(file_path)

    def select_output(self):
        """选择输出文件路径"""
        if not self.pdf1_path.get():
            messagebox.showerror("错误", "请先选择第一个PDF文件")
            return

        first_pdf_dir = os.path.dirname(self.pdf1_path.get())
        first_pdf_name = os.path.splitext(os.path.basename(self.pdf1_path.get()))[0]
        default_name = f"{first_pdf_name}_合并.pdf"

        output_path = filedialog.asksaveasfilename(
            title="选择输出路径和文件名",
            initialdir=first_pdf_dir,
            initialfile=default_name,
            defaultextension=".pdf",
            filetypes=[("PDF files", "*.pdf")]
        )

        if output_path:
            self.output_path.set(output_path)

    def select_file(self, title):
        """选择PDF文件并验证"""
        file_path = filedialog.askopenfilename(
            title=title,
            filetypes=[("PDF files", "*.pdf"), ("All files", "*.*")]
        )

        if not file_path:  # 用户取消了选择
            return None

        # 验证文件是否为有效的PDF
        if not is_valid_pdf(file_path):
            messagebox.showerror("错误", "选择的文件不是有效的PDF文件，请重新选择。")
            return None

        return file_path

    def merge_pdfs(self):
        """执行PDF合并操作"""
        pdf1_path = self.pdf1_path.get()
        pdf2_path = self.pdf2_path.get()
        output_path = self.output_path.get()

        # 检查文件是否已存在，如果存在则询问是否覆盖
        if os.path.exists(output_path):
            response = messagebox.askyesno("文件已存在", f"文件 '{os.path.basename(output_path)}' 已存在，是否要覆盖?")
            if not response:
                self.status_var.set("用户取消覆盖操作")
                return

        # 禁用按钮，防止重复点击
        self.merge_button.config(state=tk.DISABLED)
        self.status_var.set("正在合并PDF文件，请稍候...")
        self.root.update()

        # 执行合并操作
        success = merge_pdfs_interlaced_reverse(pdf1_path, pdf2_path, output_path)

        # 如果标准方法失败，尝试替代方法
        if not success:
            self.status_var.set("标准合并方法失败，尝试替代方法...")
            self.root.update()
            success = try_alternative_merge(pdf1_path, pdf2_path, output_path)

        # 显示结果消息
        if success:
            messagebox.showinfo("完成", f"PDF合并完成！\n结果已保存到: {output_path}")
            self.status_var.set("合并完成")
        else:
            messagebox.showerror("错误", "PDF合并失败。文件可能已损坏或格式不受支持。")
            self.status_var.set("合并失败")

        # 重新启用按钮
        self.merge_button.config(state=tk.NORMAL)

def merge_pdfs_interlaced_reverse(pdf1_path, pdf2_path, output_path):
    """合并两个PDF文件，将第二个PDF的页面逆序插入到第一个PDF中"""
    try:
        # 读取两个PDF文件（使用非严格模式以处理某些损坏的PDF）
        pdf1_reader = PyPDF2.PdfReader(pdf1_path, strict=False)
        pdf2_reader = PyPDF2.PdfReader(pdf2_path, strict=False)

        # 获取两个PDF的极数
        pdf1_pages = len(pdf1_reader.pages)
        pdf2_pages = len(pdf2_reader.pages)

        print(f"第一个PDF文件有 {pdf1_pages} 页")
        print(f"第二个PDF文件有 {pdf2_pages} 页")

        # 检查PDF是否为空
        if pdf1_pages == 0 or pdf2_pages == 0:
            raise ValueError("一个或多个PDF文件没有页面")

        # 创建一个新的PDF写入对象
        pdf_writer = PyPDF2.PdfWriter()

        # 将页面按要求进行合并
        page_list = []  # 存储页面的列表

        # 先将第一个PDF的所有页面加入列表
        for i in range(pdf1_pages):
            page_list.append(('pdf1', i))

        # 然后按逆序将第二个PDF的页面插入到相应位置
        for i in range(min(pdf1_pages, pdf2_pages)):
            # 计算插入位置：在第i页之后插入
            insert_pos = i * 2 + 1  # 每次插入位置会随着已插入页面增加而向后移动
            page_list.insert(insert_pos, ('pdf2', pdf2_pages - 1 - i))  # 逆序取第二个PDF的页面

        # 如果第二个PDF的页数比第一个PDF多，将剩余页面添加到末尾
        if pdf2_pages > pdf1_pages:
            for i in range(pdf1_pages, pdf2_pages):
                page_list.append(('pdf2', pdf2_pages - 1 - i))

        # 按照构建好的顺序添加页面到PDF writer
        for source, page_idx in page_list:
            if source == 'pdf1':
                page = pdf1_reader.pages[page_idx]
                pdf_writer.add_page(page)
                print(f"添加第一个PDF的第{page_idx+1}页")
            else:
                page = pdf2_reader.pages[page_idx]
                pdf_writer.add_page(page)
                print(f"添加第二个PDF的第{page_idx+1}页")

        # 保存合并后的PDF
        with open(output_path, 'wb') as out:
            pdf_writer.write(out)

        print(f"\n合并完成，结果保存为 {output_path}")
        return True

    except PyPDF2.errors.PdfReadError as e:
        print(f"PDF读取错误: {e}")
        return False
    except Exception as e:
        print(f"处理过程中出现错误: {e}")
        return False

def try_alternative_merge(pdf1_path, pdf2_path, output_path):
    """尝试使用替代方法合并PDF（逐页处理）"""
    try:
        # 使用二进制模式读取文件
        with open(pdf1_path, 'rb') as f1, open(pdf2_path, 'rb') as f2:
            pdf1_reader = PyPDF2.PdfReader(f1, strict=False)
            pdf2_reader = PyPDF2.PdfReader(f2, strict=False)

            pdf1_pages = len(pdf1_reader.pages)
            pdf2_pages = len(pdf2_reader.pages)

            pdf_writer = PyPDF2.PdfWriter()

            # 逐页处理，避免内存问题
            for i in range(max(pdf1_pages, pdf2_pages)):
                if i < pdf1_pages:
                    try:
                        page = pdf1_reader.pages[i]
                        pdf_writer.add_page(page)
                        print(f"添加第一个PDF的第{i+1}页")
                    except:
                        print(f"跳过第一个PDF的第{i+1}页（可能已损坏）")

                if i < pdf2_pages:
                    try:
                        # 逆序添加第二个PDF的页面
                        page_idx = pdf2_pages - 1 - i
                        page = pdf2_reader.pages[page_idx]
                        pdf_writer.add_page(page)
                        print(f"添加第二个PDF的第{page_idx+1}页")
                    except:
                        print(f"跳过第二个PDF的第{page_idx+1}页（可能已损坏）")

            # 保存合并后的PDF
            with open(output_path, 'wb') as out:
                pdf_writer.write(out)

            return True

    except Exception as e:
        print(f"替代方法也失败: {e}")
        return False

def main():
    """主函数"""
    root = tk.Tk()
    app = PDFMergerGUI(root)
    root.mainloop()

if __name__ == "__main__":
    main()